package handler

import (
	"context"
	"fmt"
	"github.com/golang/protobuf/ptypes/wrappers"
	itemC "kop/modules/item/client"
	"time"

	"kop/framework/errors"
	"kop/libs/database"
	"kop/libs/redis"
	"kop/modules/captain/configuration/train"
	"kop/modules/captain/entity"
	"kop/modules/captain/models"
	"kop/pb"
	"kop/pb/service"
	"kop/util/rand"

	activityC "kop/modules/activity/client"
	questC "kop/modules/quest/client"
	roleC "kop/modules/role/client"
)

const TrainSecond = 4 * 3600

func (h *CaptainServiceHandler) GetTrainSeats(_ context.Context, req *service.RoleRequest, resp *pb.TrainSeats) error {

	var data = models.GetTrainSeats(database.DB, req.RoleID)
	resp.TrainSeats = make([]*pb.TrainSeat, 0, len(data))

	var seat int32 = 0
	for _, v := range data {

		if v.Seat > seat {
			seat = v.Seat
		}

		resp.TrainSeats = append(resp.TrainSeats, buildPbTrainSeat(v))
	}

	resp.UnlockDiamond = train.GetTrainCost(seat)
	return nil
}

//func (h *CaptainServiceHandler) GetTrainSeat(_ context.Context, req *service.DefaultRequest, resp *pb.TrainSeat) error {
//
//	*resp = models.BuildPbTrainSeat(models.GetTrainSeat(database.DB, req.RoleID, req.Value))
//	return nil
//}

func (h *CaptainServiceHandler) TrainUnlock(_ context.Context, req *service.DefaultRequest, resp *pb.TrainSeat) error {

	*resp = *buildPbTrainSeat(models.UnlockTrainSeat(database.DB, req.RoleID, req.Value))
	return nil
}

func (h *CaptainServiceHandler) Train(ctx context.Context, req *pb.APITrainRequest, resp *pb.TrainSeat) error {

	var roleID = h.GetRoleID(ctx)

	var trainSeats = models.GetTrainSeats(database.DB, roleID)

	for _, v := range trainSeats {
		if v.CaptainID == req.CaptainID {
			return fmt.Errorf("captain is train")
		}
	}

	for _, trainSeat := range trainSeats {
		if trainSeat.Seat == req.Seat {

			if trainSeat.CaptainID != 0 {
				return fmt.Errorf("seat %d be used", resp.Seat)
			}

			var _, err = models.GetCaptain(database.DB, roleID, req.CaptainID)
			if err != nil {
				return err
			}

			trainSeat.CaptainID = req.CaptainID
			models.SaveTrainSeat(database.DB, &trainSeat)

			*resp = *buildPbTrainSeat(trainSeat)

			// quest main
			//go questC.Train(roleID)
			// quest daily
			go questC.DailyQuestTrain(roleID)
			// quest of activity
			activityC.AddPoints(roleID, h.GetServerID(ctx), activityC.Train, 1)
			return nil
		}

	}

	return errors.ParamError
}

func (h *CaptainServiceHandler) TrainFinish(ctx context.Context, req *wrappers.Int32Value, resp *pb.APITrainFinishReply) (err error) {

	var roleID = h.GetRoleID(ctx)
	var trainSeat = models.GetTrainSeat(database.DB, roleID, req.Value)

	if trainSeat.CaptainID < 1 {
		return errors.ParamError
	}

	if int32(time.Now().Sub(trainSeat.UpdatedAt).Seconds()) < TrainSecond {
		return errors.New("train time not enough")
	}

	var session = database.DB.Begin()
	if session.Error != nil {
		return session.Error
	}

	defer func() {
		if r := recover(); r != nil {
			err = r.(error)
		}
		if err != nil {
			session.Rollback()
		}
	}()

	var c = models.New(roleID)
	var captain = c.GetEntity(trainSeat.CaptainID)

	var itemNumber, exp = int32(1), int32(100)
	var n = redis.GetTodayNumber(fmt.Sprintf("TrainLuck%d", roleID))
	var luck = n < int(roleC.GetVIP(roleID).Benediction)
	if luck && rand.IsWin(0.15) {

		redis.SetTodayNumber(fmt.Sprintf("TrainLuck%d", roleID), n+1)
		itemNumber, exp = itemNumber*3, exp*3
	}

	captain.Exp += exp
	models.Save(session, captain)

	trainSeat.CaptainID = 0
	models.SaveTrainSeat(session, &trainSeat)

	if err = session.Commit().Error; err != nil {
		return err
	}

	// 奖励碎片
	var piece = pb.RawItem{ItemID: captain.CaptainID + 103000, Number: itemNumber}

	resp.Exp = exp
	resp.RawItem = &piece
	resp.Captain = c.ToMessage(captain.CaptainID)
	resp.TrainSeat = buildPbTrainSeat(trainSeat)

	_ = itemC.AddItem(roleID, piece.ItemID, piece.Number)
	return nil
}

func buildPbTrainSeat(trainSeat entity.TrainSeat) *pb.TrainSeat {

	var res = pb.TrainSeat{
		Seat:      trainSeat.Seat,
		CaptainID: trainSeat.CaptainID,
	}

	if res.CaptainID > 0 {

		var diff = int32(time.Now().Sub(trainSeat.UpdatedAt).Seconds())
		if diff < TrainSecond {
			res.Second = TrainSecond - diff
		}
	}

	return &res
}
